package com.im.service.conversation.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.im.codec.pack.conversation.DeleteConversationPack;
import com.im.codec.pack.conversation.UpdateConversationPack;
import com.im.service.config.AppConfig;
import com.im.common.constant.Constants;
import com.im.common.enums.exception.ConversationErrorCode;
import com.im.common.enums.ConversationTypeEnum;
import com.im.common.enums.command.ConversationEventCommand;
import com.im.common.exception.BusinessException;
import com.im.common.model.ClientInfo;
import com.im.common.model.SyncReq;
import com.im.common.model.SyncResp;
import com.im.common.model.message.MessageReadedContent;
import com.im.service.conversation.entity.ImConversationSetEntity;
import com.im.service.conversation.mapper.ImConversationSetMapper;
import com.im.service.conversation.model.DeleteConversationReq;
import com.im.service.conversation.model.UpdateConversationReq;
import com.im.service.utils.MessageProducer;
import com.im.service.utils.RedisSeq;
import com.im.service.utils.WriteUserSeq;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;

/**
 * ConversationServiceImpl 是实现 ConversationService 接口的具体实现类
 */
@Service
public class ConversationServiceImpl implements ConversationService {

    @Autowired
    private ImConversationSetMapper imConversationSetMapper;
    @Autowired
    private MessageProducer messageProducer;
    @Autowired
    private AppConfig appConfig;
    @Autowired
    private RedisSeq redisSeq;
    @Autowired
    private WriteUserSeq writeUserSeq;

    /**
     * 将 fromId 和 toId 组合成 conversationId
     *
     * @param type   会话类型
     * @param fromId 发送者ID
     * @param toId   接收者ID
     * @return 组合后的 conversationId
     */
    public String convertConversationId(Integer type, String fromId, String toId) {
        return type + "_" + fromId + "_" + toId;
    }

    /**
     * 将消息标记为已读
     *
     * @param messageReadedContent 消息已读内容
     */
    public void messageMarkRead(MessageReadedContent messageReadedContent) {
        String toId = messageReadedContent.getToId();
        if (messageReadedContent.getConversationType() == ConversationTypeEnum.GROUP.getCode()) {
            toId = messageReadedContent.getGroupId();
        }
        String conversationId = convertConversationId(messageReadedContent.getConversationType(), messageReadedContent.getFromId(), toId);
        // 查询是否存在该会话
        QueryWrapper<ImConversationSetEntity> query = new QueryWrapper<>();
        query.eq("conversation_id", conversationId);
        query.eq("app_id", messageReadedContent.getAppId());
        ImConversationSetEntity imConversationSetEntity = imConversationSetMapper.selectOne(query);
        // 如果不存在，则新建一个会话
        if (imConversationSetEntity == null) {
            imConversationSetEntity = new ImConversationSetEntity();
            long seq = redisSeq.doGetSeq(messageReadedContent.getAppId() + ":" + Constants.SeqConstants.Conversation);
            imConversationSetEntity.setConversationId(conversationId);
            BeanUtils.copyProperties(messageReadedContent, imConversationSetEntity);
            imConversationSetEntity.setReadedSequence(messageReadedContent.getMessageSequence());
            imConversationSetEntity.setToId(toId);
            imConversationSetEntity.setSequence(seq);
            imConversationSetMapper.insert(imConversationSetEntity);
            writeUserSeq.writeUserSeq(messageReadedContent.getAppId(), messageReadedContent.getFromId(), Constants.SeqConstants.Conversation, seq);
        }
        // 如果存在，则更新该会话的已读消息序号和 seq
        else {
            long seq = redisSeq.doGetSeq(messageReadedContent.getAppId() + ":" + Constants.SeqConstants.Conversation);
            imConversationSetEntity.setSequence(seq);
            imConversationSetEntity.setReadedSequence(messageReadedContent.getMessageSequence());
            imConversationSetMapper.readMark(imConversationSetEntity);
            writeUserSeq.writeUserSeq(messageReadedContent.getAppId(), messageReadedContent.getFromId(), Constants.SeqConstants.Conversation, seq);
        }
    }

    /**
     * 删除会话
     *
     * @param req 删除会话请求
     * @return 删除结果
     */
    public void deleteConversation(DeleteConversationReq req) {
        // 如果配置为同步模式，则向客户端发送删除会话事件
        if (appConfig.getDeleteConversationSyncMode() == 1) {
            DeleteConversationPack pack = new DeleteConversationPack();
            pack.setConversationId(req.getConversationId());
            messageProducer.sendToUserExceptClient(req.getFromId(), ConversationEventCommand.CONVERSATION_DELETE, pack, new ClientInfo(req.getAppId(), req.getClientType(), req.getImei()));
        }
    }

    /**
     * 更新会话信息
     *
     * @param req 更新会话请求
     * @return 更新结果
     */
    public void updateConversation(UpdateConversationReq req) {
        // 如果更新参数为空，则返回参数错误
        if (req.getIsTop() == null && req.getIsMute() == null) {
            throw new BusinessException(ConversationErrorCode.CONVERSATION_UPDATE_PARAM_ERROR);
        }
        QueryWrapper<ImConversationSetEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("conversation_id", req.getConversationId());
        queryWrapper.eq("app_id", req.getAppId());
        ImConversationSetEntity imConversationSetEntity = imConversationSetMapper.selectOne(queryWrapper);

        // 如果会话存在，则更新会话信息
        if (imConversationSetEntity != null) {
            long seq = redisSeq.doGetSeq(req.getAppId() + ":" + Constants.SeqConstants.Conversation);

            if (req.getIsMute() != null) {
                imConversationSetEntity.setIsTop(req.getIsTop());
            }
            if (req.getIsMute() != null) {
                imConversationSetEntity.setIsMute(req.getIsMute());
            }
            imConversationSetEntity.setSequence(seq);
            imConversationSetMapper.update(imConversationSetEntity, queryWrapper);
            writeUserSeq.writeUserSeq(req.getAppId(), req.getFromId(), Constants.SeqConstants.Conversation, seq);

            // 向客户端发送更新会话事件
            UpdateConversationPack pack = new UpdateConversationPack();
            pack.setConversationId(req.getConversationId());
            pack.setIsMute(imConversationSetEntity.getIsMute());
            pack.setIsTop(imConversationSetEntity.getIsTop());
            pack.setSequence(seq);
            pack.setConversationType(imConversationSetEntity.getConversationType());
            messageProducer.sendToUserExceptClient(req.getFromId(), ConversationEventCommand.CONVERSATION_UPDATE, pack, new ClientInfo(req.getAppId(), req.getClientType(), req.getImei()));
        }
    }

    /**
     * 同步会话列表
     *
     * @param req 同步请求
     * @return 同步结果
     */
    public SyncResp syncConversationSet(SyncReq req) {
        // 如果 maxLimit 超过 100，则将其设为 100
        if (req.getMaxLimit() > 100) {
            req.setMaxLimit(100);
        }
        SyncResp<ImConversationSetEntity> resp = new SyncResp<>();
        QueryWrapper<ImConversationSetEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("from_id", req.getOperator());
        queryWrapper.gt("sequence", req.getLastSequence());
        queryWrapper.eq("app_id", req.getAppId());
        queryWrapper.last(" limit " + req.getMaxLimit());
        queryWrapper.orderByAsc("sequence");
        List<ImConversationSetEntity> list = imConversationSetMapper.selectList(queryWrapper);

        // 如果查询结果不为空，则设置同步结果的 dataList、maxSequence 和 completed 属性
        if (!CollectionUtils.isEmpty(list)) {
            ImConversationSetEntity maxSeqEntity = list.get(list.size() - 1);
            resp.setDataList(list);
            // 设置最大 seq
            Long friendShipMaxSeq = imConversationSetMapper.geConversationSetMaxSeq(req.getAppId(), req.getOperator());
            resp.setMaxSequence(friendShipMaxSeq);
            // 设置是否拉取完毕
            resp.setCompleted(maxSeqEntity.getSequence() >= friendShipMaxSeq);
            return resp;
        }

        // 如果查询结果为空，则设置同步结果的 completed 属性为 true
        resp.setCompleted(true);
        return resp;

    }
}
